/*
 * rule_lib.c
 *
 *  Created on: 2012/10/24
 *      Author: shenming
 */

#include <stdio.h>
#include <stdlib.h>
#include "core.h"

AST getFstUnpChdExp(AST exp) {
	U4 kind = CExpression.getOpKind(exp);
	while (CExpressionOpKind.isParentheseExp(kind)) {
		exp = CExpression.getLeftNode(exp);
		kind = CExpression.getOpKind(exp);
	}
	return exp;
}

static BOOL isDnCastExpr(AST exp) {
	AST castType = 0;
	AST valueInfo = 0;
	AST childExp = 0;
	AST tmpExp = 0;
	DOUBLE dbVal;

	castType = CExpression.getTypeInfo(exp);
	if (!CTypeInfo.isBasicType(castType)) {
		return FALSE;
	}
	if (!CTypeInfo.isInteger(castType)) {
		return FALSE;
	}

	tmpExp = exp;
	/*check cast op*/
	exp = CExpression.getLeftNode(tmpExp);
	if (!CExpressionOpKind.isDeclaration(CExpression.getOpKind(exp))) {
		return FALSE;
	}

	/*check casted op*/
	exp = CExpression.getRightNode(tmpExp);
	exp = getFstUnpChdExp(exp);
	if (!CExpressionOpKind.isAdditiveOp(CExpression.getOpKind(exp))) {
		return FALSE;
	}

	tmpExp = exp;
	/*right : rounded off value: 0.5,0.50,...*/
	exp = CExpression.getRightNode(tmpExp);
	if (!CExpressionOpKind.isConstantNumber(CExpression.getOpKind(exp))) {
		return FALSE;
	}
	valueInfo = CExpression.getPrimaryConstValue(exp);
	if (!CValueInfo.isFloating(valueInfo)) {
		return FALSE;
	}
	dbVal = CValueInfo.getFloatingValue(valueInfo);
	/*to be changed: compare float number*/
	if (dbVal - 0.5 != 0) {
		return FALSE;
	}

	/*find phy or phy +/- offset*/
	exp = CExpression.getLeftNode(tmpExp);
	exp = getFstUnpChdExp(exp);
	while (!CExpressionOpKind.isParentheseExp(CExpression.getOpKind(exp))) {
		if (exp == 0) {
			return FALSE;
		}
		if (!(CMultiOpKind.isMultiplicative(CExpression.getOpKind(exp))
				|| CMultiOpKind.isDivision(CExpression.getOpKind(exp)))) {
			return FALSE;
		}
		/*no checking LSB according to original COX1219*/
		exp = CExpression.getLeftNode(exp);
	}

	/*check phy or phy +/- offset*/
	exp = getFstUnpChdExp(exp);
	if (CExpressionOpKind.isAdditiveOp(CExpression.getOpKind(exp))) {
		/*check current exp is phy*/
		childExp = CExpression.getLeftNode(exp);
		while (!CExpressionOpKind.isParentheseExp(
				CExpression.getOpKind(childExp))) {
			childExp = CExpression.getLeftNode(childExp);
			/*if current exp is phy,will not check phy exp*/
			if (childExp == 0) {
				return TRUE;
			}
		}

		/*with offset,check offset*/
		if (childExp != CExpression.getLeftNode(exp)) {
			return FALSE;
		}
		/*check offset*/
		childExp = CExpression.getRightNode(exp);
		childExp = getFstUnpChdExp(childExp);
		/*check if only constant*/
		if (!CExpressionOpKind.isConstantNumber(
				CExpression.getOpKind(childExp))) {
			return FALSE;
		}
	} else {
		/*check current exp is phy*/
		childExp = CExpression.getLeftNode(exp);
		while (!CExpressionOpKind.isParentheseExp(
				CExpression.getOpKind(childExp))) {
			childExp = CExpression.getLeftNode(childExp);
			if (childExp == 0) {
				break;
			}
		}
		if (childExp > 0) {
			return FALSE;
		}
		/*if no () in phy exp,will not check phy exp*/
	}

	return TRUE;
}

BOOL isDnInitExp(AST expInfo) {
	U4 expKind;

	expInfo = getFstUnpChdExp(expInfo);
	expKind = CExpression.getOpKind(expInfo);

	if (CExpressionOpKind.isCastOp(expKind)) {
		return isDnCastExpr(expInfo);
	} else if (CAdditiveOpKind.isSubtraction(expKind)) {
		/*left*/
		expInfo = CExpression.getLeftNode(expInfo);
		expInfo = getFstUnpChdExp(expInfo);
		if (!CExpressionOpKind.isConstantNumber(
				CExpression.getOpKind(expInfo))) {
			return FALSE;
		}
		/*right*/
		expInfo = CExpression.getRightNode(expInfo);
		expInfo = getFstUnpChdExp(expInfo);
		if (!CExpressionOpKind.isCastOp(CExpression.getOpKind(expInfo))) {
			return FALSE;
		}
		return isDnCastExpr(expInfo);
	} else {
		return FALSE;
	}

	return TRUE;
}

BOOL isConstInitExp(AST index, AST * expInfo) {
	AST typeSpecifier = 0;
	AST declarator = 0;
	AST type = 0;
	AST explist = 0;

	if (index <= 0) {
		return FALSE;
	}

	if (!CDeclaration.isOrdinaryDeclaration(index)) {
		return FALSE;
	}

	declarator = CDeclaration.getDeclarator(index);
	if (declarator <= 0) {
		return FALSE;
	}
	if (!CDeclarator.isInitialExpDeclarator(declarator)) {
		return FALSE;
	}

	typeSpecifier = CDeclaration.getTypeSpecifier(index);
	if (typeSpecifier <= 0) {
		return FALSE;
	}

	type = CTypeSpecifier.getTypeInfo(typeSpecifier);
	if (type <= 0) {
		return FALSE;
	}
	if (!CTypeInfo.isBasicType(type)) {
		return FALSE;
	}
	if (!CTypeInfo.isInteger(type)) {
		return FALSE;
	}
	if (!CTypeInfo.isConst(type)) {
		return FALSE;
	}
	if (!CTypeInfo.isVolatile(type)) {
		return FALSE;
	}

	explist = CDeclarator.initExp_getInitExp(declarator);
	if (explist <= 0) {
		return FALSE;
	}
	if (!CInitializer.isConstatnt(explist)) {
		return FALSE;
	}
	if (!CInitializer.isExpInitializer(explist)) {
		return FALSE;;
	}

	*expInfo = CInitializer.getExpression(explist);
	return TRUE;
}

BOOL hasSideEffect(AST exp) {
	U4 expKind = 0;
	AST childExp = 0;
	if (exp <= 0) {
		return FALSE;
	}
	expKind = CExpression.getOpKind(exp);
	if (CPostfixOpKind.isFunctionCall(expKind)
			|| CPostfixOpKind.isPostIncrement(expKind)
			|| CPostfixOpKind.isPostDecrement(expKind)
			|| CUnaryOpKind.isPreIncrement(expKind)
			|| CUnaryOpKind.isPreDecrement(expKind)
			|| CExpressionOpKind.isAssignmentOp(expKind)) {
		return TRUE;
	}
	childExp = CExpression.getLeftNode(exp);
	if (hasSideEffect(childExp)) {
		return TRUE;
	}
	childExp = CExpression.getRightNode(exp);
	if (hasSideEffect(childExp)) {
		return TRUE;
	}
	return FALSE;
}

BOOL isStandardFor(AST stmt) {
	AST forExp1 = CStatement.for_getInitExp(stmt);
	AST forExp2 = CStatement.for_getCondExp(stmt);
	AST forExp3 = CStatement.for_getIncExp(stmt);
	AST exp = 0;
	U4 expKind = 0;
	exp = getFstUnpChdExp(forExp3);
	expKind = CExpression.getOpKind(exp);
	if (CPostfixOpKind.isPostIncrement(expKind)
			|| CPostfixOpKind.isPostDecrement(expKind)
			|| CUnaryOpKind.isPreIncrement(expKind)
			|| CUnaryOpKind.isPreDecrement(expKind)
			|| CExpressionOpKind.isAssignmentOp(expKind)) {
		//the third expression is formatted
	} else {
		return FALSE;
	}
	exp = getFstUnpChdExp(forExp1);
	expKind = CExpression.getOpKind(exp);
	if (exp == 0 || CExpressionOpKind.isAssignmentOp(expKind)) {
		//the first expression is formatted
	} else {
		return FALSE;
	}
	exp = getFstUnpChdExp(forExp2);
	expKind = CExpression.getOpKind(exp);
	if (CExpressionOpKind.isRelationalOp(expKind)
			|| CExpressionOpKind.isEqualityOp(expKind)) {
		//the second expression is formatted
	} else {
		return FALSE;
	}
	return TRUE;
}

AST getForLoopCounter(AST stmt) {
	AST forExp3 = CStatement.for_getIncExp(stmt);
	AST symbol = 0;
	AST exp = 0;
	U4 expKind = 0;
	exp = getFstUnpChdExp(forExp3);
	expKind = CExpression.getOpKind(exp);
	if (CPostfixOpKind.isPostIncrement(expKind)
			|| CPostfixOpKind.isPostDecrement(expKind)
			|| CUnaryOpKind.isPreIncrement(expKind)
			|| CUnaryOpKind.isPreDecrement(expKind)
			|| CExpressionOpKind.isAssignmentOp(expKind)) {
		exp = CExpression.getLeftNode(exp);
		exp = getFstUnpChdExp(exp);
		expKind = CExpression.getOpKind(exp);
		if (CExpressionOpKind.isIdentifier(expKind)) {
			symbol = CExpression.getPrimarySymbol(exp);
		}
	}
	return symbol;
}

